#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import json
import time
import threading
import random
from datetime import datetime
from flask import Flask, render_template, jsonify
from flask_socketio import SocketIO, emit
import paho.mqtt.client as mqtt
import logging

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

app = Flask(__name__)
app.config['SECRET_KEY'] = 'warehouse_fire_monitoring_secret'
socketio = SocketIO(app, cors_allowed_origins="*", async_mode='eventlet')

# MQTT配置
MQTT_BROKER = "47.82.107.28"  # 公共EMQX服务器，您可以替换为自己的服务器
MQTT_PORT = 1883
MQTT_USERNAME = "admin"  # 如果需要认证，请填写用户名
MQTT_PASSWORD = "public"  # 如果需要认证，请填写密码

# MQTT主题配置
TOPICS = {
    "temperature": "warehouse/sensors/temperature",
    "smoke": "warehouse/sensors/smoke", 
    "alarm": "warehouse/alarm",
    "device_status": "warehouse/devices/status",
    "system_status": "warehouse/system/status"
}

# 全局数据存储
sensor_data = {
    "zones": {
        "A": {"temperature": 23.5, "smoke": 0.02, "status": "normal"},
        "B": {"temperature": 24.1, "smoke": 0.01, "status": "normal"},
        "C": {"temperature": 22.8, "smoke": 0.03, "status": "normal"},
        "D": {"temperature": 23.9, "smoke": 0.02, "status": "normal"}
    },
    "devices": {
        "main_controller": {"status": "normal", "message": "正常运行"},
        "communication": {"status": "normal", "message": "信号良好"},
        "backup_power": {"status": "normal", "message": "100%"},
        "water_pump": {"status": "normal", "message": "待机状态"}
    },
    "system": {
        "status": "normal",
        "total_sensors": 156,
        "sprinklers": 24,
        "today_alarms": 0,
        "availability": 99.8
    },
    "alarms": []
}

# MQTT客户端
mqtt_client = None

def on_connect(client, userdata, flags, rc):
    """MQTT连接回调"""
    if rc == 0:
        logger.info("成功连接到MQTT服务器")
        # 订阅所有主题
        for topic_name, topic in TOPICS.items():
            client.subscribe(topic)
            logger.info(f"订阅主题: {topic}")
    else:
        logger.error(f"连接MQTT服务器失败，错误码: {rc}")

def on_message(client, userdata, msg):
    """MQTT消息接收回调"""
    try:
        topic = msg.topic
        payload = json.loads(msg.payload.decode())
        logger.info(f"收到MQTT消息 - 主题: {topic}, 数据: {payload}")
        
        # 处理不同类型的消息
        if "temperature" in topic:
            handle_temperature_data(payload)
        elif "smoke" in topic:
            handle_smoke_data(payload)
        elif "alarm" in topic:
            handle_alarm_data(payload)
        elif "devices" in topic:
            handle_device_status(payload)
        elif "system" in topic:
            handle_system_status(payload)
            
        # 通过WebSocket广播数据更新
        socketio.emit('data_update', {
            'type': 'mqtt_data',
            'topic': topic,
            'data': payload,
            'timestamp': datetime.now().isoformat()
        })
        
    except Exception as e:
        logger.error(f"处理MQTT消息时出错: {e}")

def handle_temperature_data(data):
    """处理温度数据"""
    zone = data.get('zone', 'A')
    temperature = data.get('value', 23.5)
    
    if zone in sensor_data['zones']:
        sensor_data['zones'][zone]['temperature'] = temperature
        
        # 检查温度报警
        if temperature > 50:
            add_alarm(f"{zone}区域温度异常: {temperature}°C", "danger")
        elif temperature > 35:
            add_alarm(f"{zone}区域温度偏高: {temperature}°C", "warning")

def handle_smoke_data(data):
    """处理烟雾数据"""
    zone = data.get('zone', 'A')
    smoke = data.get('value', 0.02)
    
    if zone in sensor_data['zones']:
        sensor_data['zones'][zone]['smoke'] = smoke
        
        # 检查烟雾报警
        if smoke > 0.1:
            add_alarm(f"{zone}区域烟雾浓度异常: {smoke}%", "danger")
        elif smoke > 0.05:
            add_alarm(f"{zone}区域烟雾浓度偏高: {smoke}%", "warning")

def handle_alarm_data(data):
    """处理报警数据"""
    message = data.get('message', '未知报警')
    level = data.get('level', 'info')
    zone = data.get('zone', '')
    
    add_alarm(message, level, zone)

def handle_device_status(data):
    """处理设备状态数据"""
    device_id = data.get('device_id')
    status = data.get('status', 'normal')
    message = data.get('message', '')
    
    if device_id in sensor_data['devices']:
        sensor_data['devices'][device_id]['status'] = status
        sensor_data['devices'][device_id]['message'] = message

def handle_system_status(data):
    """处理系统状态数据"""
    for key, value in data.items():
        if key in sensor_data['system']:
            sensor_data['system'][key] = value

def add_alarm(message, level="info", zone=""):
    """添加报警记录"""
    alarm = {
        'time': datetime.now().strftime('%H:%M:%S'),
        'message': message,
        'level': level,
        'zone': zone
    }
    
    sensor_data['alarms'].insert(0, alarm)
    
    # 保持最多50条记录
    if len(sensor_data['alarms']) > 50:
        sensor_data['alarms'] = sensor_data['alarms'][:50]
    
    # 更新今日报警次数
    if level in ['warning', 'danger']:
        sensor_data['system']['today_alarms'] += 1

def init_mqtt():
    """初始化MQTT客户端"""
    global mqtt_client
    
    mqtt_client = mqtt.Client()
    mqtt_client.on_connect = on_connect
    mqtt_client.on_message = on_message
    
    if MQTT_USERNAME and MQTT_PASSWORD:
        mqtt_client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD)
    
    try:
        mqtt_client.connect(MQTT_BROKER, MQTT_PORT, 60)
        mqtt_client.loop_start()
        logger.info("MQTT客户端启动成功")
    except Exception as e:
        logger.error(f"MQTT客户端启动失败: {e}")

def simulate_data():
    """模拟数据生成（用于演示）"""
    while True:
        try:
            # 模拟温度数据
            for zone in ['A', 'B', 'C', 'D']:
                temp_data = {
                    'zone': zone,
                    'value': round(random.uniform(20, 30), 1),
                    'timestamp': datetime.now().isoformat()
                }
                
                smoke_data = {
                    'zone': zone,
                    'value': round(random.uniform(0.01, 0.05), 3),
                    'timestamp': datetime.now().isoformat()
                }
                
                # 模拟发送MQTT消息
                if mqtt_client:
                    mqtt_client.publish(TOPICS['temperature'], json.dumps(temp_data))
                    mqtt_client.publish(TOPICS['smoke'], json.dumps(smoke_data))
            
            # 偶尔模拟报警
            if random.random() < 0.1:  # 10%概率
                alarm_data = {
                    'message': f"{random.choice(['A', 'B', 'C', 'D'])}区域传感器自检正常",
                    'level': 'info',
                    'zone': random.choice(['A', 'B', 'C', 'D']),
                    'timestamp': datetime.now().isoformat()
                }
                if mqtt_client:
                    mqtt_client.publish(TOPICS['alarm'], json.dumps(alarm_data))
            
            time.sleep(5)  # 每5秒更新一次
            
        except Exception as e:
            logger.error(f"模拟数据生成出错: {e}")
            time.sleep(5)

@app.route('/')
def index():
    """主页路由"""
    return render_template('index.html')

@app.route('/api/data')
def get_data():
    """获取当前数据API"""
    return jsonify(sensor_data)

@socketio.on('connect')
def handle_connect():
    """WebSocket连接处理"""
    logger.info('客户端已连接')
    emit('connected', {'data': '连接成功'})
    # 发送当前数据
    emit('data_update', {
        'type': 'initial_data',
        'data': sensor_data,
        'timestamp': datetime.now().isoformat()
    })

@socketio.on('disconnect')
def handle_disconnect():
    """WebSocket断开连接处理"""
    logger.info('客户端已断开连接')

@socketio.on('request_data')
def handle_request_data():
    """处理数据请求"""
    emit('data_update', {
        'type': 'requested_data',
        'data': sensor_data,
        'timestamp': datetime.now().isoformat()
    })

@socketio.on('system_action')
def handle_system_action(data):
    """处理系统操作"""
    action = data.get('action')
    logger.info(f'收到系统操作请求: {action}')
    
    if action == 'self_test':
        add_alarm('系统自检开始', 'info')
        # 模拟自检过程
        threading.Timer(2.0, lambda: add_alarm('系统自检完成，所有设备正常', 'info')).start()
    elif action == 'emergency_stop':
        add_alarm('紧急停止按钮被按下', 'warning')
        sensor_data['system']['status'] = 'emergency_stop'
    elif action == 'reset':
        add_alarm('系统复位完成', 'info')
        sensor_data['system']['status'] = 'normal'
    elif action == 'generate_report':
        add_alarm('正在生成系统报告...', 'info')
    
    # 广播系统状态更新
    socketio.emit('data_update', {
        'type': 'system_action',
        'action': action,
        'data': sensor_data,
        'timestamp': datetime.now().isoformat()
    })

if __name__ == '__main__':
    # 初始化MQTT
    init_mqtt()
    
    # 启动数据模拟线程
    data_thread = threading.Thread(target=simulate_data, daemon=True)
    data_thread.start()
    
    # 启动Flask应用
    logger.info("启动仓库火灾监控系统...")
    socketio.run(app, host='0.0.0.0', port=5000, debug=False)

